package com.googlecode.openrtp.grizzly;

import com.google.inject.AbstractModule;
import com.google.inject.Provides;
import com.google.inject.assistedinject.FactoryModuleBuilder;
import com.google.inject.multibindings.MapBinder;
import com.google.inject.multibindings.Multibinder;
import com.google.inject.name.Names;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Set;
import org.glassfish.grizzly.filterchain.Filter;
import org.glassfish.grizzly.filterchain.FilterChain;
import org.glassfish.grizzly.filterchain.FilterChainBuilder;
import org.glassfish.grizzly.filterchain.TransportFilter;
import org.glassfish.grizzly.nio.transport.UDPNIOTransport;
import org.glassfish.grizzly.nio.transport.UDPNIOTransportBuilder;
import com.googlecode.openrtp.grizzly.rtcp.RtcpManager;
import com.googlecode.openrtp.grizzly.rtcp.filter.RtcpByeFilter;
import com.googlecode.openrtp.grizzly.rtcp.filter.RtcpFilter;
import com.googlecode.openrtp.grizzly.rtcp.filter.RtcpSenderReportFilter;
import com.googlecode.openrtp.grizzly.rtcp.filter.RtcpSourceDescriptionFilter;
import com.googlecode.openrtp.grizzly.rtp.RtpManager;
import com.googlecode.openrtp.grizzly.session.SessionContextListener;
import com.googlecode.openrtp.grizzly.rtp.filter.RtpFilter;
import com.googlecode.openrtp.grizzly.rtp.filter.MpegAudioPacketizerFilter;
import com.googlecode.openrtp.grizzly.rtp.filter.RtpPacketGenerateFilter;
import com.googlecode.openrtp.grizzly.rtp.filter.RtpSessionFilter;
import com.googlecode.openrtp.grizzly.server.GrizzlyRtcpServer;
import com.googlecode.openrtp.grizzly.server.GrizzlyRtpServer;
import com.googlecode.openrtp.grizzly.session.DefaultRtpSession;
import com.googlecode.openrtp.grizzly.session.DefaultRtpSessionManager;
import com.googlecode.openrtp.grizzly.util.BufferUtil;
import com.googlecode.openrtp.spi.RtpSession;
import com.googlecode.openrtp.spi.RtpSessionManager;
import com.googlecode.openrtp.spi.annotation.Rtcp;
import com.googlecode.openrtp.spi.annotation.RtcpPayload;
import com.googlecode.openrtp.spi.annotation.Rtp;
import com.googlecode.openrtp.spi.rtcp.RtcpHeaderPacket;
import com.googlecode.openrtp.spi.server.Server;
import com.googlecode.openrtp.util.serviceloader.Service;
import org.glassfish.grizzly.Buffer;
import org.glassfish.grizzly.attributes.AttributeBuilder;

/**
 *
 * @author jocke
 */
@Service(value = AbstractModule.class)
public class GrizzlyRtpModule extends AbstractModule {

    @Override
    protected void configure() {

        bind(Server.class).annotatedWith(Names.named("RTP")).to(GrizzlyRtpServer.class);
        bind(Server.class).annotatedWith(Names.named("RTCP")).to(GrizzlyRtcpServer.class);
        bind(RtpSessionManager.class).to(DefaultRtpSessionManager.class);

        bind(Buffer.class).toProvider(BufferUtil.class);

        Multibinder<Filter> rtpFilters = Multibinder.newSetBinder(binder(), Filter.class, Rtp.class);
        rtpFilters.addBinding().to(RtpFilter.class);
        rtpFilters.addBinding().to(FileStoreFilter.class);
        rtpFilters.addBinding().to(RtpSessionFilter.class);
        rtpFilters.addBinding().to(RtpPacketGenerateFilter.class);
        rtpFilters.addBinding().to(MpegAudioPacketizerFilter.class);

        Multibinder<Filter> rtcpFilters = Multibinder.newSetBinder(binder(), Filter.class, Rtcp.class);
        rtcpFilters.addBinding().to(RtcpFilter.class);

        MapBinder<Integer, Filter> rtcpBodyFilters = MapBinder.newMapBinder(binder(), Integer.class, Filter.class, RtcpPayload.class);
        rtcpBodyFilters.addBinding(RtcpHeaderPacket.PT.SENDER_REPORT).to(RtcpSenderReportFilter.class);
        rtcpBodyFilters.addBinding(RtcpHeaderPacket.PT.SOURCE_DESC).to(RtcpSourceDescriptionFilter.class);
        rtcpBodyFilters.addBinding(RtcpHeaderPacket.PT.BYE).to(RtcpByeFilter.class);

        Multibinder<SessionContextListener> contextListenerBinder = Multibinder.newSetBinder(binder(), SessionContextListener.class);
        contextListenerBinder.addBinding().to(RtcpManager.class);
        contextListenerBinder.addBinding().to(RtpManager.class);

        install(new FactoryModuleBuilder()
                .implement(RtpSession.class, DefaultRtpSession.class)
                .build(RtpSessionFactory.class));

    }

    @Rtcp
    @Provides
    public UDPNIOTransport createRtcpTransport(@Rtcp Set<Filter> filters) {
        List<Filter> sortedFilters = new ArrayList<>(filters);
        Collections.sort(sortedFilters, FilterPriorityComparator.getInstance());
        FilterChain filterChain = FilterChainBuilder.stateless()
                .add(new TransportFilter())
                .addAll(sortedFilters)
                .build();
        UDPNIOTransport transport = UDPNIOTransportBuilder.newInstance()
                .setAttributeBuilder(AttributeBuilder.DEFAULT_ATTRIBUTE_BUILDER)
                .build();
        transport.setProcessor(filterChain);
        transport.setReuseAddress(true);
        return transport;
    }

    @Rtp
    @Provides
    public UDPNIOTransport createRtpTransport(@Rtp Set<Filter> filters) {
        List<Filter> sortedFilters = new ArrayList<>(filters);
        Collections.sort(sortedFilters, FilterPriorityComparator.getInstance());
        FilterChain filterChain = FilterChainBuilder.stateless()
                .add(new TransportFilter())
                .addAll(sortedFilters)
                .build();
        UDPNIOTransport transport = UDPNIOTransportBuilder.newInstance()
                .setAttributeBuilder(AttributeBuilder.DEFAULT_ATTRIBUTE_BUILDER)
                .build();
        transport.setProcessor(filterChain);
        transport.setReuseAddress(true);
        return transport;
    }
}
